package com.baijiayun.live.ui.speakpanel

import android.annotation.SuppressLint
import android.graphics.drawable.Drawable
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.SeekBar
import android.widget.Toast
import androidx.appcompat.content.res.AppCompatResources
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import com.baijiayun.glide.Glide
import com.baijiayun.glide.request.target.SimpleTarget
import com.baijiayun.glide.request.transition.Transition
import com.baijiayun.live.ui.R
import com.baijiayun.live.ui.activity.LiveRoomBaseActivity
import com.baijiayun.live.ui.activity.LiveRoomRouterListener
import com.baijiayun.live.ui.getFormatterTime
import com.baijiayun.live.ui.isAdmin
import com.baijiayun.live.ui.speakerlist.item.Playable
import com.baijiayun.live.ui.speakerlist.item.RemoteItem
import com.baijiayun.live.ui.speakerlist.item.SwitchableStatus
import com.baijiayun.live.ui.speakerlist.item.SwitchableType
import com.baijiayun.live.ui.unDisplayViewSize
import com.baijiayun.livecore.context.LPConstants
import com.baijiayun.livecore.context.LPConstants.MediaState
import com.baijiayun.livecore.models.LPUserModel
import com.baijiayun.livecore.models.imodels.IMediaModel
import com.baijiayun.livecore.models.imodels.IUserModel
import com.baijiayun.livecore.models.launch.LPAwardConfig
import com.baijiayun.livecore.ppt.util.AliCloudImageUtil
import com.baijiayun.livecore.utils.CommonUtils
import com.baijiayun.livecore.utils.LPRxUtils
import com.baijiayun.livecore.utils.ToastCompat
import com.baijiayun.livecore.viewmodels.impl.LPSpeakQueueViewModel
import com.baijiayun.liveuibase.utils.ThemeDataUtil
import com.baijiayun.liveuibase.widgets.dialog.AwardPopupWindow
import com.baijiayun.liveuibase.widgets.dialog.ThemeMaterialDialogBuilder
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import kotlinx.android.synthetic.main.bjy_layout_cover_player_controller.view.*
import kotlinx.android.synthetic.main.bjy_layout_item_video.view.*
import java.util.concurrent.TimeUnit

/**
 * Created by yongjiaming on 2019-10-18
 * Describe: 大班课远端视频
 */
class RemoteVideoItem(
    rootView: ViewGroup,
    media: IMediaModel,
    routerListener: LiveRoomRouterListener
) : RemoteItem(rootView, media, routerListener), Playable, LifecycleObserver {

    private var disposableOfTimer: Disposable? = null
    private var videoCloseBgUrl: String? = ""
    private var originParams: LinearLayout.LayoutParams? = null
    private var awardPopupWindow: AwardPopupWindow? = null
    private var isMax = false

    private val speakerNameTv by lazy {
        container.item_local_speaker_name
    }
    private var playerControllerContainer: ViewGroup? = null
    private val coverViewStub by lazy {
        container.cover_view_stub
    }
    private var videoState = MediaState.Normal
    private var audioState = MediaState.Normal
    private val disposables = CompositeDisposable()

    init {
        container = LayoutInflater.from(context)
            .inflate(R.layout.bjy_layout_item_video, rootView, false) as ViewGroup
        videoContainer = container.item_local_speaker_avatar_container
        loadingContainer = container.item_speak_speaker_loading_container
        loadingImageView = container.item_speak_speaker_loading_img
        registerClickEvent(container)
        refreshNameTable()
        observeActions()
        if (mediaModel.user is LPUserModel) {
            videoCloseBgUrl = (mediaModel.user as LPUserModel).cameraCover
        }
        if (liveRoom != null && isAdmin(liveRoom) && mediaModel.user.type == LPConstants.LPUserType.Student) {
            container.item_award_container.setOnClickListener {
                if (awardPopupWindow != null) {
                    // 多种，弹窗
                    awardPopupWindow!!.run {
                        if (isShowing) {
                            dismiss()
                        } else {
                            setUserModel(mediaModel.user)
                            show(it)
                        }
                    }
                } else {
                    routerListener.requestAward(mediaModel.user)
                }
            }
            container.item_award_container.visibility = View.VISIBLE
        }
        initAward()
        if (liveRoom?.speakQueueVM?.enableWarmingUpVideo() == true && coverViewStub.parent != null) {
            playerControllerContainer = coverViewStub.inflate() as ConstraintLayout
        }
        playerControllerContainer?.run {
            cover_player_controller_image_view_play_state.setImageDrawable(AppCompatResources.getDrawable(context, R.drawable.bjy_live_sel_play_state))
            cover_player_controller_image_view_play_zoom.setImageDrawable(AppCompatResources.getDrawable(context, R.drawable.bjy_live_sel_play_zoom))
            cover_player_controller_seek_bar.setOnSeekBarChangeListener(object :
                SeekBar.OnSeekBarChangeListener {
                override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                    if (fromUser) {
                        player?.seekRtmpStream(identity, progress)
                        onPlayingProgressChange(progress)
                    }
                }

                override fun onStartTrackingTouch(seekBar: SeekBar?) {
                    //不用实现
                }

                override fun onStopTrackingTouch(seekBar: SeekBar?) {
                    //不用实现
                }
            })
            cover_player_controller_image_view_play_state.setOnClickListener {
                if (it.isSelected) {
                    player?.resumeRtmpStream(identity)
                } else {
                    player?.pauseRtmpStream(identity)
                }
                it.isSelected = !it.isSelected
            }
            cover_player_controller_image_view_play_zoom.setOnClickListener {
                switchToFullScreen(!it.isSelected)
            }
        }
        if (enableShowResolutionText()) {
            setCDNResolution(if (liveRoom.partnerConfig.liveDefaultCdnResolution == 0) LPConstants.LPCDNResolution.ORIGINAL else LPConstants.LPCDNResolution.HIGH)
        }
    }

    override fun switchToFullScreen(isFullScreen: Boolean) {
        super.switchToFullScreen(isFullScreen)
        if (mediaModel?.isWarmingUpVideo == true) {
            playerControllerContainer?.cover_player_controller_image_view_play_zoom?.isSelected =
                isFullScreen
        }
    }

    private fun initAward() {
        val awardConfigs: Array<LPAwardConfig> = routerListener.liveRoom.awardConfigs
            ?: return
        var enableAwardTypeCount = 0
        var availableAward: LPAwardConfig? = null
        for (lpAwardConfig in awardConfigs) {
            if (lpAwardConfig.isEnable == 1) {
                availableAward = lpAwardConfig
                enableAwardTypeCount++
            }
        }
        if (enableAwardTypeCount <= 1 && availableAward != null) {
            // 仅一种启用，使用对应logo
            container.item_award_icon.setImageDrawable(
                AppCompatResources.getDrawable(
                    context,
                    R.drawable.base_ic_award_like
                )
            )
            // 保存 当前 LPAwardConfig
        } else {
            // 使用钻石
            container.item_award_icon.setImageResource(R.drawable.base_ic_video_award_default)
            // 初始化 AwardPopupWindow
            awardPopupWindow = AwardPopupWindow(context) { user, awardKey ->
                routerListener.requestAward(
                    user,
                    awardKey
                )
            }
        }
    }

    fun observeActions() {
        disposables.add(liveRoom.observableOfUserUpdate
            .observeOn(AndroidSchedulers.mainThread())
            .filter {
                TextUtils.equals(it.userId, mediaModel.user.userId) ||
                        (liveRoom.speakQueueVM.isMixModeOn && identity == LPSpeakQueueViewModel.FAKE_MIX_STREAM_USER_ID)
            }
            .subscribe {
                setVideoCloseUrl(it.cameraCover)
                if (it.audioState != null) {
                    audioState = it.audioState
                }
                if (it.videoState != null) {
                    videoState = it.videoState
                }
                if (container.item_status_placeholder_ll.visibility == View.VISIBLE) {
                    container.item_cdn_resolution.visibility = View.INVISIBLE
                    when (videoState) {
                        MediaState.Normal -> {
                            showVideoClose()
                        }
                        MediaState.Unavailable -> {
                            container.item_status_placeholder_tv.text =
                                context.getString(R.string.pad_camera_unavailable)
                            setVideoCloseImageState(
                                false,
                                ContextCompat.getDrawable(
                                    context,
                                    R.drawable.base_ic_video_camera_error
                                )
                            )
                        }
                        MediaState.Backstage -> {
                            container.item_status_placeholder_tv.text =
                                context.getString(R.string.pad_camera_backstage)
                            setVideoCloseImageState(
                                false,
                                ContextCompat.getDrawable(
                                    context,
                                    R.drawable.base_ic_video_backstage
                                )
                            )
                        }
                        MediaState.PermissionDeny -> {
                            container.item_status_placeholder_tv.text =
                                context.getString(R.string.pad_camera_permissiondeny)
                            setVideoCloseImageState(
                                false,
                                ContextCompat.getDrawable(
                                    context,
                                    R.drawable.base_ic_video_occupied
                                )
                            )
                        }
                        else -> {
                            container.item_status_placeholder_tv.text =
                                context.getString(R.string.pad_camera_occupied)
                            setVideoCloseImageState(
                                false,
                                ContextCompat.getDrawable(
                                    context,
                                    R.drawable.base_ic_video_occupied
                                )
                            )
                        }
                    }
                }
            })
    }

    override fun initView() {
        // do nothing
    }

    @SuppressLint("SetTextI18n")
    override fun refreshNameTable() {
        val remoteUser = mediaModel.user
        val userName = CommonUtils.getEncodePhoneNumber(remoteUser.name)
        when (remoteUser.type) {
            LPConstants.LPUserType.Teacher -> {
                var teacherLabel = liveRoom.customizeTeacherLabel
                teacherLabel =
                    if (TextUtils.isEmpty(teacherLabel)) context.getString(R.string.live_teacher_hint) else "($teacherLabel)"
                speakerNameTv.text = userName + teacherLabel
            }
            LPConstants.LPUserType.Assistant -> {
                var assistantLabel = liveRoom.customizeAssistantLabel
                assistantLabel = if (TextUtils.isEmpty(assistantLabel)) "" else "($assistantLabel)"
                if (isPresenter()) {
                    assistantLabel = "(主讲)"
                }
                speakerNameTv.text = userName + assistantLabel
            }
            else -> speakerNameTv.text = userName
        }
        if (mediaModel.isWarmingUpVideo) {
            speakerNameTv.visibility = View.GONE
            playerControllerContainer?.visibility = View.VISIBLE
        } else {
            speakerNameTv.visibility = View.VISIBLE
            playerControllerContainer?.visibility = View.GONE
        }
    }

    private fun isPresenter() = (liveRoom.presenterUser != null
            && liveRoom.presenterUser.userId == mediaModel?.user?.userId)
            || mediaModel?.user?.userId == LPSpeakQueueViewModel.FAKE_MIX_STREAM_USER_ID


    override fun showVideoClose() {
        videoContainer.removeAllViews()
        container.item_status_placeholder_ll.visibility = View.VISIBLE
        container.item_cdn_resolution.visibility = View.INVISIBLE
        when (videoState) {
            MediaState.Normal -> {
                container.item_status_placeholder_tv.text =
                    context.getString(R.string.pad_camera_closed)
                if (videoCloseBgUrl.isNullOrEmpty()) {
                    setVideoCloseImageState(
                        false,
                        ContextCompat.getDrawable(context, R.drawable.base_ic_video_camera_mute)
                    )
                } else {
                    val placeHoderView = unDisplayViewSize(container.item_status_placeholder_iv)
                    videoCloseBgUrl =
                        if (placeHoderView[0] <= 0) videoCloseBgUrl else AliCloudImageUtil.getScaledUrl(
                            videoCloseBgUrl, AliCloudImageUtil.SCALED_MFIT,
                            placeHoderView[0], placeHoderView[1]
                        )
                    Glide.with(context).load(videoCloseBgUrl)
                        .into(object : SimpleTarget<Drawable>() {
                            override fun onResourceReady(
                                resource: Drawable,
                                transition: Transition<in Drawable>?
                            ) {
                                setVideoCloseImageState(true, resource)
                            }

                            override fun onLoadFailed(errorDrawable: Drawable?) {
                                setVideoCloseImageState(
                                    false,
                                    ContextCompat.getDrawable(
                                        context,
                                        R.drawable.base_ic_video_camera_mute
                                    )
                                )
                                super.onLoadFailed(errorDrawable)
                            }
                        })
                }
            }
            MediaState.Unavailable -> {
                container.item_status_placeholder_tv.text =
                    context.getString(R.string.pad_camera_unavailable)
                setVideoCloseImageState(
                    false,
                    ContextCompat.getDrawable(context, R.drawable.base_ic_video_camera_error)
                )
            }
            MediaState.Backstage -> {
                container.item_status_placeholder_tv.text =
                    context.getString(R.string.pad_camera_backstage)
                setVideoCloseImageState(
                    false,
                    ContextCompat.getDrawable(context, R.drawable.base_ic_video_backstage)
                )
            }
            MediaState.PermissionDeny -> {
                container.item_status_placeholder_tv.text =
                    context.getString(R.string.pad_camera_permissiondeny)
                setVideoCloseImageState(
                    false,
                    ContextCompat.getDrawable(context, R.drawable.base_ic_video_occupied)
                )
            }
            MediaState.Occupied -> {
                container.item_status_placeholder_tv.text =
                    context.getString(R.string.pad_camera_occupied)
                setVideoCloseImageState(
                    false,
                    ContextCompat.getDrawable(context, R.drawable.base_ic_video_occupied)
                )
            }
        }
    }

    private fun setVideoCloseImageState(isCustom: Boolean, videoCloseDrawable: Drawable?) {
        if (!isCustom && originParams != null) {
            container.item_status_placeholder_iv.layoutParams = originParams
            container.item_status_placeholder_iv.scaleType = ImageView.ScaleType.FIT_CENTER
            originParams = null
        } else if (isCustom && originParams == null) {
            val params =
                container.item_status_placeholder_iv.layoutParams as LinearLayout.LayoutParams
            originParams = LinearLayout.LayoutParams(params)
            params.height = ViewGroup.LayoutParams.MATCH_PARENT
            params.width = ViewGroup.LayoutParams.MATCH_PARENT
            container.item_status_placeholder_iv.layoutParams = params
            container.item_status_placeholder_iv.scaleType = ImageView.ScaleType.CENTER_CROP
        }
        val llParams = container.item_status_placeholder_ll.layoutParams
        llParams.height = if (isCustom) ViewGroup.LayoutParams.MATCH_PARENT else 0
        container.item_status_placeholder_ll.layoutParams = llParams
        container.item_status_placeholder_iv.setImageDrawable(videoCloseDrawable)
        container.item_status_placeholder_tv.visibility = if (isCustom) View.GONE else View.VISIBLE
    }

    override fun showVideoOpen() {
        container.item_status_placeholder_ll.visibility = View.GONE
        hideNickName(isInFullScreen || status == SwitchableStatus.MaxScreen)
        container.item_cdn_resolution.visibility = if (enableShowResolutionText()) View.VISIBLE else View.INVISIBLE
    }

    override fun getSwitchableType(): SwitchableType = when {
        isPresenterVideo -> {
            SwitchableType.MainItem
        }
        //辅助摄像头当做ppt处理
        identity.contains("_1") -> {
            if (routerListener.liveRoom.partnerConfig.enableShowPPTWithAssistCameraOn) {
                SwitchableType.SpeakItem
            } else {
                SwitchableType.PPT
            }
        }
        else -> {
            SwitchableType.SpeakItem
        }
    }

    override fun enableClearScreen() = true

    override fun switchPPTVideoSync() {
        if (liveRoom.isSyncPPTVideo && (liveRoom.isTeacherOrAssistant || liveRoom.isGroupTeacherOrAssistant)
            && isPresenterVideo && liveRoom.isClassStarted
        ) {
            showSwitchDialog()
        } else {
            switch2FullScreenLocal()
        }
    }

    override fun hideNickName(hide: Boolean) {
        super.hideNickName(hide)
        speakerNameTv.visibility =
            if (hide || mediaModel?.isWarmingUpVideo == true) View.GONE else View.VISIBLE
        container.item_cdn_resolution.visibility = if (enableShowResolutionText() && !hide) View.VISIBLE else View.INVISIBLE
    }

    override fun isPresenterVideo() = if (liveRoom.speakQueueVM.isMixModeOn) {
        if (routerListener.liveRoom.speakQueueVM.presenter.isNullOrEmpty()) {
            false
        } else {
            identity == LPSpeakQueueViewModel.FAKE_MIX_STREAM_USER_ID
        }
    } else {
        identity == routerListener.liveRoom.presenterUser?.userId
    }

    private fun switch2FullScreenLocal() {
        super.switchPPTVideoSync()
        isMax = true
    }

    private fun switch2FullScreenSync() {
        liveRoom.requestPPTVideoSwitch(isPresenterVideo)
        switch2FullScreenLocal()
    }

    private fun showSwitchDialog() {
        if (context == null || context !is LiveRoomBaseActivity) {
            return
        }
        if (context.isFinishing || context.isDestroyed) {
            return
        }
        context.let {
            ThemeMaterialDialogBuilder(it)
                .title(getString(R.string.live_exit_hint_title))
                .content(getString(R.string.live_pad_sync_video_ppt))
                .positiveText(R.string.live_pad_switch_sync)
                .negativeText(R.string.live_pad_switch_local)
                .negativeColor(
                    ThemeDataUtil.getColorFromThemeConfigByAttrId(
                        it,
                        R.attr.base_theme_dialog_negative_text_color
                    )
                )
                .onPositive { _, _ -> switch2FullScreenSync() }
                .onNegative { _, _ -> switch2FullScreenLocal() }
                .show()
        }
    }

    override fun getUser(): IUserModel = mediaModel.user

    override fun notifyAwardChange(count: Int) {
        if (count > 0) {
            container.item_award_container.visibility = View.VISIBLE
            container.item_award_count.text = count.toString()
        }
    }

    fun refreshUserName(userName: String, type: LPConstants.LPUserType) {
        val user = mediaModel.user
        if (user is LPUserModel) {
            user.name = userName
            user.type = type
        }
        refreshNameTable()
    }

    override fun setMediaModel(_mediaModel: IMediaModel) {
        mediaModel = _mediaModel
        if (_mediaModel.user is LPUserModel) {
            val user = _mediaModel.user as LPUserModel
            videoCloseBgUrl = user.cameraCover
            if (user.audioState != null) {
                audioState = user.audioState
            }
            if (user.videoState != null) {
                videoState = user.videoState
            }
        }
        refreshItemType()
        refreshNameTable()
    }

    private fun setVideoCloseUrl(url: String? = "") {
        videoCloseBgUrl = url
        if (container.item_status_placeholder_ll.visibility == View.VISIBLE) {
            showVideoClose()
        }
    }

    override fun onReadyToPlay(mediaId: String?) {
        super.onReadyToPlay(mediaId)
        if (mediaModel?.isWarmingUpVideo == true) {
            startTimer(mediaId)
            playerControllerContainer?.run {
                cover_player_controller_image_view_play_state.isSelected = false
                cover_player_controller_seek_bar.max = player?.getDurationOfRtmpStream(mediaId) ?: 0
                cover_player_controller_text_view_curr_time.text =
                    getFormatterTime(player?.getCurrentPositionOfRtmpStream(mediaId) ?: 0)
                cover_player_controller_text_view_total_time.text =
                    getFormatterTime(player?.getDurationOfRtmpStream(mediaId) ?: 0)
            }
        } else {
            LPRxUtils.dispose(disposableOfTimer)
        }
    }

    private fun startTimer(mediaId: String?) {
        LPRxUtils.dispose(disposableOfTimer)
        disposableOfTimer = Observable.interval(500, TimeUnit.MILLISECONDS)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe {
                onPlayingProgressChange(player?.getCurrentPositionOfRtmpStream(mediaId) ?: 0)
            }
    }

    fun onPlayingProgressChange(
        currentTimeSeconds: Int
    ) {
        playerControllerContainer?.cover_player_controller_seek_bar?.progress =
            currentTimeSeconds
        playerControllerContainer?.cover_player_controller_text_view_curr_time?.text =
            getFormatterTime(currentTimeSeconds)
    }

    override fun onPlayComplete(mediaId: String?) {
        super.onPlayComplete(mediaId)
        if (mediaModel?.isWarmingUpVideo == true) {
            playerControllerContainer?.cover_player_controller_image_view_play_state?.isSelected =
                true
            player?.seekRtmpStream(mediaId, 0)
        }
    }

    override fun onBufferingUpdate(mediaId: String?, percent: Int) {
        super.onBufferingUpdate(mediaId, percent)
        if (mediaModel?.isWarmingUpVideo == true) {
            playerControllerContainer?.cover_player_controller_seek_bar?.secondaryProgress =
                (percent * 1.0f * (playerControllerContainer?.cover_player_controller_seek_bar?.max?:0) / 100).toInt()
        }
    }

    override fun setCDNResolutionText(resolutionText: String, isMaxInScreen: Boolean) {
        super.setCDNResolutionText(resolutionText, isMaxInScreen)
        container.item_cdn_resolution.text = resolutionText
        container.item_cdn_resolution.visibility = if (isMaxInScreen) View.INVISIBLE else View.VISIBLE
        if (isMaxInScreen) {
            ToastCompat.showToast(context, context.getString(R.string.bjy_live_cdn_resolution_switch_tip, resolutionText), Toast.LENGTH_SHORT)
        }
    }


    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun onDestroy() {
        onRemove()
        LPRxUtils.dispose(disposables)
        if (loadingListener != null) {
            player.removePlayerListener(loadingListener)
            loadingListener = null
        }
    }

    /**
     * 手动删除item生命周期<=fragment
     */
    fun onRemove() {
        if (dialog?.isShowing == true) {
            dialog?.dismiss()
        }
    }
}